home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
LANG
/
C
/
GCC
/
V2-4-5
/
GCCEXTSR
/
Virtual
/
!Virtual
/
c
/
pager
< prev
next >
Wrap
Text File
|
1993-09-06
|
13KB
|
522 lines
/*
* pager.c
* Part of the !Virtual distribution
* (c) bdb/nas/fo, 1992-3
*/
#include "swis.h"
#include "swiv.h"
#include "wimp.h"
#include "virtual.h"
#include "lib.h"
#include "output.h"
#include "pager.h"
/* #define DEBUG */
void Initourmem(WKSP *w)
{
int i;
w->stacktop = (char *)alloc(STACKSIZE)+STACKSIZE;
swi(OS_ReadMemMapInfo, OUT(R0|R1), &w->pagesize, &w->numpages);
w->pageshift = 15;
if (w->pagesize == K32/2) w->pageshift = 14;
if (w->pagesize == K32/4) w->pageshift = 13;
w->numplaces = PLACE(M24);
w->ourmem = alloc(sizeof(int) * w->numplaces);
w->oldpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
w->newpages = alloc(sizeof(PAGEENTRY)*(w->numpages + 1));
FindPages(w);
w->nslots = 0; /* page file empty */
w->index = alloc(sizeof(int)*w->numplaces);
for ( i=PLACE(K32); i<w->numplaces; i++)
{ w->ourmem[i] = TAGLOC(ABORT, 0);
}
w->losepage = 0;
}
void SetWimpMemMap(WKSP *w)
{
int i;
#ifdef DEBUG
printf("Places %d..%d match wimp map\n",PLACE(K32),w->numourpages+PLACE(K32));
#endif
for ( i = 0; i<w->numourpages; i++ )
{ w->newpages[i].addr = ADDR(i)+K32;
w->newpages[i].access = ACCESS_READWRITE;
w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY,i);
}
for ( i=w->numourpages+PLACE(K32); i<w->numplaces; i++ )
w->ourmem[i] = TAGLOC(ABORT, 0);
for (i=0;i<w->nslots;i++)
w->index[i] = -1;
}
void Finishourmem(WKSP *w)
{
free(w->oldpages);
free(w->newpages);
free(w->ourmem);
free(w->index);
}
int SetVirtualSlot(WKSP *w, int size)
{ int i,m;
i = PLACE(K32);
m = i + PLACE(size);
#ifdef DEBUG
printf("Places %d..%d abort->zerofill\n",i,m);
#endif
for (;i<m;i++)
if (TAG(w->ourmem[i])==ABORT)
w->ourmem[i] = TAGLOC(ZERO,0);
return size;
}
void virtualmem(WKSP *w)
{
swi(OS_SetMemMapEntries, IN(R0), w->newpages);
}
void normalmem(WKSP *w)
{
swi(OS_SetMemMapEntries, IN(R0), w->oldpages);
}
/* Find us a set of pysical pages, preserving newpages[0..numourpages].addr,access */
void FindPages(WKSP *w)
{
int i;
int appspace;
int a, b;
for (i = 0; i<w->numpages ; i++)
w->oldpages[i].pagenum = i;
w->oldpages[w->numpages].pagenum = -1;
swi(OS_ReadMemMapEntries, IN(R0), w->oldpages);
swi(OS_ChangeEnvironment, IN(R0|R1)|OUT(R1), 14, 0, &appspace);
w->numourpages = PLACE(appspace - K32);
b = w->numourpages; /* We accumulate pages that must be moved out the way here */
for (i = 0; i<w->numpages; i++)
{ if (w->oldpages[i].addr < K32) /* OS workspace will get protected */
/*w->newpages[b++] = w->oldpages[i] */;
else if (w->oldpages[i].addr < appspace) /* Useable page */
{ a = PLACE(w->oldpages[i].addr-K32); /* its current place */
w->newpages[a].pagenum = i; /* it becomes our page */
}
else if (w->oldpages[i].addr < M24) /* page needs moving */
w->newpages[b++] = w->oldpages[i];
}
for (i=0; i<w->numourpages; i++)
{ w->oldpages[i].pagenum = w->newpages[i].pagenum;
w->oldpages[i].addr = ADDR(i)+K32;
w->oldpages[i].access = ACCESS_READWRITE;
}
for (i = w->numourpages; i<b; i++)
{ w->oldpages[i] = w->newpages[i];
if (w->newpages[i].addr<K32)
w->newpages[i].access = ACCESS_READONLY;
else
{ w->newpages[i].addr = DUMPADDR;
w->newpages[i].access = ACCESS_BAD;
} }
w->oldpages[b].pagenum = -1;
w->newpages[b].pagenum = -1;
}
static int pageout(WKSP *w, int page, int addr)
{
int place, Normaddr, slot;
place = PLACE(addr);
Normaddr = w->oldpages[page].addr;
slot = LOC(w->ourmem[place]);
switch (TAG(w->ourmem[place]))
{ case DIRTY:
for (slot = 0; slot<w->nslots; slot++)
if (w->index[slot] == -1)
break;
if (slot>=w->nslots)
{ w->nslots = slot+1;
#ifdef DEBUG
printf("nslots = %d\n",w->nslots);
#endif
}
swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 1, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
/* FALL THROUGH */
case SAVED:
w->index[slot] = place;
w->ourmem[place] = TAGLOC(PAGED, slot);
break;
default:
printf("*** ILLEGAL page out tag page %d addr %d place %d Normaddr %d slot %d tag %d\n",
page,addr,place,Normaddr,slot,TAG(w->ourmem[place]));
RealDoOff(w);
break;
}
#ifdef DEBUG
printf("Paging place %d out from page %d to slot %d\n",place,page,slot);
#endif
return page;
}
static int findpageout(WKSP *w)
{
int addr, page;
loop:
page = w->losepage;
if (++w->losepage >= w->numourpages)
w->losepage = 0;
addr = w->newpages[page].addr;
if (addr == DUMPADDR)
return page;
if (addr & LOCKADDRBIT)
goto loop;
return pageout(w,page,addr);
}
static void pagein(WKSP *w, int page, int place, int write)
{ int Normaddr = w->oldpages[page].addr;
int slot = LOC(w->ourmem[place]);
swi(OS_GBPB, IN(R0|R1|R2|R3|R4), 3, w->pagefile, Normaddr, w->pagesize, ADDR(slot));
w->newpages[page].addr = ADDR(place);
if (write)
{ w->newpages[page].access = ACCESS_READWRITE;
w->index[slot] = -1;
w->ourmem[place] = TAGLOC(DIRTY, page);
}
else
{ w->newpages[page].access = ACCESS_READONLY;
w->index[slot] = page;
w->ourmem[place] = TAGLOC(SAVED, slot);
}
#ifdef DEBUG
printf("Paging place %d in to page %d from slot %d %s",place,page,slot,write?"writeable":"readonly");
#endif
}
/*
* First page out all DIRTY places whose address is not as RISC OS expects
* Then page in all place which should be in that page.
*/
void FixMemoryPages(WKSP *w)
{
int i;
for (i = 0; i < w->numourpages; i++)
if (w->newpages[i].addr != ADDR(i) + K32 &&
w->newpages[i].access != ACCESS_BAD)
switch (TAG(w->ourmem[PLACE(w->newpages[i].addr)])) {
case DIRTY:
pageout(w, i, w->newpages[i].addr);
break;
} /* switch */
for (i = 0; i < w->numourpages; i++) {
if (w->newpages[i].addr != ADDR(i) + K32) {
switch (TAG(w->ourmem[i+PLACE(K32)])) {
case PAGED:
pagein(w, i, i + PLACE(K32), 1);
break;
case ZERO:
/*
* This page was just recieved from the wimp by a wimplsot drag.
* I'm not really sure if the tag, the place recieves here
* should be DIRTY; maybe ZERO is ok. But, to be consistent with Brian's
* code in SetWimpMemMap, all places paged in at the right page,
* get the DIRTY tag.
*/
w->ourmem[i+PLACE(K32)] = TAGLOC(DIRTY, i);
w->newpages[i].addr = ADDR(i) + K32;
w->newpages[i].access = ACCESS_READWRITE;
break;
} /* switch */
}
}
}
void SetRealMem(WKSP*w, int size)
{
int newnumourpages=PLACE(size);
int i,newslot;
if (newnumourpages<2)
newnumourpages=2;
if (newnumourpages!=w->numourpages)
{ for (i = newnumourpages; i < w->numourpages; i++)
{
if (w->newpages[i].addr!=DUMPADDR)
pageout(w, i, w->newpages[i].addr);
}
swi(Wimp_SlotSize,IN(R0|R1)|OUT(R0),ADDR(newnumourpages),-1,&newslot);
newnumourpages = PLACE(newslot);
for (i = w->numourpages; i<newnumourpages; i++)
{ w->newpages[i].addr=DUMPADDR;
w->newpages[i].access=ACCESS_BAD;
}
/*
* When the user drags our slotbar, we often will receive more than one
* wimp_MSETSLOT message at once. In the old code, w->losepage would then
* be set at the *end* of a big block of DUMPADDR pages. This is a waste.
* The code below ensures w->losepage is always on the first DUMPADDR page.
*/
if (w->numourpages < newnumourpages) {
for (i = 0; i < newnumourpages; i++)
if (w->newpages[i].addr == DUMPADDR) {
w->losepage = i;
break;
}
}
else
w->losepage = 0;
w->numourpages = newnumourpages;
#ifdef DEBUG
printf("numourpages=%d\n",newnumourpages);
#endif
} }
static int GetPlace(WKSP *w, int place, int write)
{ int page,slot;
page = LOC(w->ourmem[place]);
switch (TAG(w->ourmem[place]))
{
case SAVED:
slot = page;
page = w->index[slot];
if (!write)
return page;
w->newpages[page].access = ACCESS_READWRITE;
w->index[slot] = -1;
w->ourmem[place]=TAGLOC(DIRTY,page);
#ifdef DEBUG
printf("Dirtying place %d in page %d free slot %d\n",place,page,slot);
#endif
if ( slot == w->nslots-1 ) /* last slot in file freed */
{ while (slot>=0 && w->index[slot]==-1)
slot--;
w->nslots = slot+1;
swi(OS_Args,IN(R0|R1|R2),3,w->pagefile,ADDR(w->nslots));
#ifdef DEBUG
printf("nslots down = %d\n",w->nslots);
#endif
}
return page;
case PAGED:
page=findpageout(w);
pagein(w, page, place, write);
return page;
case ZERO:
page=findpageout(w);
w->ourmem[place] = TAGLOC(DIRTY, page);
w->newpages[page].addr = ADDR(place);
w->newpages[page].access = ACCESS_READWRITE;
#ifdef DEBUG
printf("Place %d gets page %d zeroed",place,page);
#endif
return page;
case DIRTY:
return page;
case ABORT:
printf("***ABORT: place %d\n",place);
return -1;
default:
printf("***ILLEGAL tag: place %d in page %d tag %d\n",place,page,TAG(w->ourmem[place]));
RealDoOff(w);
return -1;
}
}
static int VGetPlace(WKSP *w, int place, int write)
{ int page;
switch (TAG(w->ourmem[place]))
{ case DIRTY:
return LOC(w->ourmem[place]);
case SAVED:
if (!write)
return LOC(w->ourmem[place]);
default:
Normal(w);
page = GetPlace(w,place,write);
Virtual(w);
return page;
}
}
RANGE Locate(WKSP *w, int start, int end)
{ int place,page;
RANGE r;
#ifdef DEBUG
printf("Locate: %x-%x",start,end);
#endif
if (start<K32)
return r.start=start,r.end=end<K32?end:K32,r;
if (start>=M24)
return r.start=start,r.end=end,r;
place=PLACE(start);
page=LOC(w->ourmem[place]);
switch (TAG(w->ourmem[place]))
{
case DIRTY:
case SAVED:
r.start=w->oldpages[page].addr+SHUFT(start);
break;
case ZERO:
r.start = 0;
break;
case ABORT:
r.start = -1;
break;
case PAGED:
r.start = (1u<<31) + ADDR(page) + SHUFT(start);
break;
}
r.end = r.start + w->pagesize - SHUFT(start);
if (r.end>r.start+end-start)
r.end = r.start+end-start;
#ifdef DEBUG
printf("==>%x-%x\n",r.start,r.end);
#endif
return r;
}
RANGE Physical(WKSP *w, int start, int end)
{ int place,page;
RANGE r;
#ifdef DEBUG
printf("Physical: %x-%x",start,end);printflush(w);
#endif
if (end<start)
RealDoOff(w);
if (start<K32)
return r.start=start,r.end=end<K32?end:K32,r;
if (start>=M24)
return r.start=start,r.end=end,r;
place=PLACE(start);
page=GetPlace(w,place,1);
if (page==-1)
return r.start=0,r.end=0,r;
r.start=w->oldpages[page].addr+SHUFT(start);
r.end = w->oldpages[page].addr+w->pagesize;
if (r.end>r.start+end-start)
r.end = r.start+end-start;
#ifdef DEBUG
printf("==>%x-%x\n",r.start,r.end); printflush(w);
#endif
return r;
}
int ToMem(WKSP *w, void *src, int dest, int size)
{ RANGE r;
int l;
while (size>0)
{ r = Physical(w, dest, dest+size);
if (!r.end)
return 0;
l=r.end-r.start;
memcpy((void*)r.start,src,l);
src=(char*)src+l;
dest+=l;
size-=l;
}
return 1;
}
int FromMem(WKSP *w, int src, void *dest, int size)
{ RANGE r;
int l;
while (size>0)
{ r = Physical(w, src, src+size);
if (!r.end)
return 0;
l=r.end-r.start;
memcpy(dest,(void *)r.start,l);
src+=l;
dest=(char*)dest+l;
size-=l;
}
return 1;
}
/* Called in virtual, svc mode to ensure range all accessable */
int ReadRange(WKSP *w, int start, int end)
{
int place1,place2,page1,page2;
if (start<K32)
return 0;
if (start>=M24)
return 1;
if (end>M24)
end=M24;
place1 = PLACE(start);
place2 = PLACE(end-1);
page1=VGetPlace(w,place1,0);
if (page1==-1)
return 0;
if (place2!=place1)
{ w->newpages[page1].addr |= LOCKADDRBIT;
page2 = VGetPlace(w,place2,0);
w->newpages[page1].addr &= ~LOCKADDRBIT;
if (page2==-1)
return 0;
}
return 1;
}
int WriteRange(WKSP *w, int start, int end)
{
int place1,place2,page1,page2;
if (start<K32)
return 0;
if (start>=M24)
return 1;
if (end>M24)
end=M24;
place1 = PLACE(start);
place2 = PLACE(end-1);
page1=VGetPlace(w,place1,1);
if (page1==-1)
return 0;
if (place2!=place1)
{ w->newpages[page1].addr |= LOCKADDRBIT;
page2 = VGetPlace(w,place2,1);
w->newpages[page1].addr &= ~LOCKADDRBIT;
if (page2==-1)
return 0;
}
return 1;
}
int ReadPtr(WKSP *w, int start)
{ int place,page;
if (start<K32)
return 0;
if (start>=M24)
return 1;
place = PLACE(start);
page=VGetPlace(w,place,0);
if (page==-1)
return 0;
return 1;
}
int WritePtr(WKSP *w, int start)
{ int place,page;
if (start<K32)
return 0;
if (start>=M24)
return 1;
place = PLACE(start);
page=VGetPlace(w,place,1);
if (page==-1)
return 0;
return 1;
}